/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package aprendizajePorRefuerzo.entorno;

import aprendizajePorRefuerzo.accion.Accion;
import aprendizajePorRefuerzo.accion.AccionGrilla;
import aprendizajePorRefuerzo.estado.Estado;
import aprendizajePorRefuerzo.estado.EstadoGrilla;
import aprendizajePorRefuerzo.reward.RewardImp;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;

/**
 *
 * @author Fernando Sorzana
 */
public class EntornoDinamicoConViento extends EntornoConViento {

    private List<EtapasEntorno> etapas;
    private int contador;
    private int posicion;
    private boolean vientoAleatorio;
    private Random random;
    
    public boolean isVientoAleatorio() {
        return vientoAleatorio;
    }

    public void setVientoAleatorio(boolean vientoAleatorio) {
        this.vientoAleatorio = vientoAleatorio;
    }

    public EntornoDinamicoConViento(int cantidadFilas, int cantidadColumnas) {
        super(cantidadFilas, cantidadColumnas);
        posicion = 1;
        contador = 0;
        etapas = new ArrayList<>();
        etapas.add(new EtapasEntorno(0));
        random = new Random(new Date().getTime());
    }

    @Override
    public RespuestaEntorno devolverRespuesta(Estado estado, Accion accion) {
        if (etapas.size() > posicion && etapas.get(posicion).getComienzo() <= contador) {
            setIntransitables(etapas.get(posicion).getIntransitables());
            setFinales(etapas.get(posicion).getFinales());
            setInicial(etapas.get(posicion).getInicial());
            posicion++;
        }
        if (!EstadoGrilla.class.isAssignableFrom(estado.getClass()) || !AccionGrilla.class.isAssignableFrom(accion.getClass())){
            return null;
        } else {
//            int columnaNueva = ((EstadoGrilla) estado).getColumna() + ((AccionGrilla) accion).getCambioColumna();
//            if (columnaNueva < 0 || columnaNueva >= getCantidadColumnas()){
//                columnaNueva = ((EstadoGrilla) estado).getColumna();
//            }
            int filaEstado = ((EstadoGrilla) estado).getFila();
            int columnaEstado = ((EstadoGrilla) estado).getColumna();
            int posibleColumnaNueva = columnaEstado + ((AccionGrilla) accion).getCambioColumna();
            int columnaNueva = columnaEstado;
            if (posibleColumnaNueva >= columnaEstado){
                for (int i = columnaEstado; i <= posibleColumnaNueva; i++){
                    EstadoGrilla estadoNuevo = new EstadoGrilla(false, true, filaEstado, i);
                    if (i >= 0 && i < getCantidadColumnas() && !getIntransitables().contains(estadoNuevo)){
                        columnaNueva = i;
                    } else {
                        break;
                    }
                }
            } else {
                for (int i = columnaEstado; i >= posibleColumnaNueva; i--){
                    EstadoGrilla estadoNuevo = new EstadoGrilla(false, true, filaEstado, i);
                    if (i >= 0 && i < getCantidadColumnas() && !getIntransitables().contains(estadoNuevo)){
                        columnaNueva = i;
                    } else {
                        break;
                    }
                }
            }
            int posibleFilaNueva = filaEstado + ((AccionGrilla) accion).getCambioFila() + calcularViento(filaEstado);
            int filaNueva = filaEstado;
            if (posibleFilaNueva >= filaEstado){
                for (int i = filaEstado; i <= posibleFilaNueva; i++){
                    EstadoGrilla estadoNuevo = new EstadoGrilla(false, true, i, columnaNueva);
                    if (i >= 0 && i < getCantidadFilas() && !getIntransitables().contains(estadoNuevo)){
                        filaNueva = i;
                    } else {
                        break;
                    }
                }
            } else {
                for (int i = filaEstado; i >= posibleFilaNueva; i--){
                    EstadoGrilla estadoNuevo = new EstadoGrilla(false, true, i, columnaNueva);
                    if (i >= 0 && i < getCantidadFilas() && !getIntransitables().contains(estadoNuevo)){
                        filaNueva = i;
                    } else {
                        break;
                    }
                }
            }
            EstadoGrilla estadoNuevo = new EstadoGrilla(false, true, filaNueva, columnaNueva);
//            if (getIntransitables().contains(estadoNuevo)){
//                return new RespuestaEntorno(getRewardComun(),estado);
//            }
            if (getFinales().contains(estadoNuevo)){
                estadoNuevo.setFinal(true);
                contador++;
            }
            RewardImp reward = estadoNuevo.esFinal() ? getRewardFinal() : getRewardComun();
            return new RespuestaEntorno(reward, estadoNuevo);
        }
    }
    
    private int calcularViento(int fila){
        int media = getViento().get(fila);
        if (vientoAleatorio){
            int valor = random.nextInt(media * 2);
            return valor;
        } else {
            return media;
        }
    }

    public void nuevaEtapa(int comienzo) {
        etapas.add(new EtapasEntorno(comienzo));
    }

    public EtapasEntorno getUltimaEtapa() {
        return etapas.get(etapas.size() - 1);
    }

    public List<EtapasEntorno> getEtapas() {
        return etapas;
    }

    public void setEtapas(List<EtapasEntorno> etapas) {
        this.etapas = etapas;
    }

    public Estado getInicial() {
        return etapas.get(posicion-1).getInicial();
    }

    @Override
    public Set<Estado> getFinales() {
        return etapas.get(posicion-1).getFinales();
    }
    
    @Override
    public Set<Estado> getIntransitables() {
        return etapas.get(posicion-1).getIntransitables();
    }
    
    public class EtapasEntorno {

        private int comienzo;
        private Estado inicial;
        private Set<Estado> intransitables;
        private Set<Estado> finales;

        public EtapasEntorno() {
            intransitables = new HashSet<Estado>();
            finales = new HashSet<Estado>();
        }

        public EtapasEntorno(int comienzo) {
            this();
            this.comienzo = comienzo;
        }

        public int getComienzo() {
            return comienzo;
        }

        public void setComienzo(int comienzo) {
            this.comienzo = comienzo;
        }

        public Set<Estado> getIntransitables() {
            return intransitables;
        }

        public void setIntransitables(Set<Estado> intransitables) {
            this.intransitables = intransitables;
        }

        public Set<Estado> getFinales() {
            return finales;
        }

        public void setFinales(Set<Estado> finales) {
            this.finales = finales;
        }

        public Estado getInicial() {
            return inicial;
        }

        public void setInicial(Estado inicial) {
            this.inicial = inicial;
        }

        public void agregarFinal(Estado estado) {
            this.finales.add(estado);
        }

        public void quitarFinal(Estado estado) {
            this.finales.remove(estado);
        }

        public void agregarIntransitable(Estado estado) {
            this.intransitables.add(estado);
        }

        public void quitarIntransitable(Estado estado) {
            this.intransitables.remove(estado);
        }

        public void agregarInicial(Estado estado) {
            this.inicial = estado;
        }

        public void quitarInicial(Estado estado) {
            this.inicial = null;
        }
    }
}
